<template>
  <div class="todoapp">
    <TodoHeader :list="showList" @addTask="addTaskHandler"></TodoHeader>
    <TodoMain @delTask="delTaskHandler" :list="showList"></TodoMain>
    <TodoFooter
      @clearDone="clearDoneHandler"
      @changeTask="changeTaskHandler"
      :list="showList"
    ></TodoFooter>
  </div>
</template>

<script>
/*  
目标1:渲染数据
1.1 在App.vue中准备数据并传入TodoMain.vue
1.2在子组件中使用v-for循环渲染li
1.3使用v-model绑定完成状态
1.4使用动态class绑定完成样式
目标2:添加数据
2.1在TodoHeader.vue中给文本框双向绑定任务名
2.2给文本框绑定键盘按下事件,捕获enter键
2.3当用户按下回车键时,将数据传递给App.vue中
2.4App.vue接收到数据后,将其添加至list
2.5在TodoHeader.vue中进行非空校验及添加后清空文本框
目标3:删除数据
3.1在TodoMain.vue中给删除按钮绑定点击事件,传入id
3.2将id传给App.vue-子传父
3.3App.vue中根据id找到对应的数据删除
目标4:统计数量
4.1在App.vue中将list传入TodoFooter.vue
4.2使用插值表达式渲染即可
目标5:切换数据
需求1:点击高亮
5.1在TodoFooter.vue中定义状态isSel,取值范围是all/yes/no
5.2动态绑定class,根据状态来决定哪个a标签应用selected类名
5.3给a标签绑定点击事件,点谁就切换对应的状态
需求2:切换数据
5.4在TodoFooter.vue中将isSel传递给App.vue
5.5父组件收到isSel后,保存到data中
5.6App.vue中定义计算属性,根据isSel的状态来筛选数据并返回
目标6:清除已完成
6.1在TodoFooter.vue中给清除已完成按钮绑定点击事件
6.2事件触发时子传父,触发父组件自定义事件,执行删除已完成的业务逻辑
6.3提供两种思路:1.找到未完成的数据,加入新数组,用新数组覆盖this.list2.找到已完成的数据,实时删除,删除一个索引自减一
目标7:数据缓存
7.1在App.vue中深度侦听list
7.2当list改变时,转成JSON字符串,存入localStorage中
7.3在list赋初始值时,从localStorage中取出,转成数组对象,空值处理
目标8:全选功能
需求1:全选影响小选
8.1在TodoHeader.vue中定义计算属性isAll完整写法
8.2将全选框和isAll双向绑定
8.3将showList从App.vue中传给TodoHeader.vue
8.4在isAll的set方法中将最新的状态设置给所有任务的isDone属性即可
需求2:小选影响全选
8.5在TodoHeader.vue中isAll的get方法里统计所有小选框的状态(如果全部选中就返回true,只要有一个没选中就返回false)
8.6如果数组中没有数据,直接返回false
*/

// 引入组件
import TodoHeader from "./components/TodoHeader.vue";
import TodoMain from "./components/TodoMain.vue";
import TodoFooter from "./components/TodoFooter.vue";

export default {
  // 注册组件
  components: {
    TodoHeader,
    TodoMain,
    TodoFooter,
  },
  data() {
    return {
      list: JSON.parse(localStorage.getItem("todolist") || "[]"),
      isSel: "all",
    };
  },
  methods: {
    addTaskHandler(taskname) {
      let id =
        this.list.length > 0 ? this.list[this.list.length - 1].id + 1 : 100;
      // 将子组件传递过来的任务添加至 list 中
      this.list.push({
        id,
        name: taskname,
        isDone: false,
      });
    },
    delTaskHandler(id) {
      // console.log('这是爸爸收到的id:', id)
      // 根据 id 找到对应的数据并删除
      // this.list.forEach((item, index) => {
      //   if (item.id === id) {
      //     this.list.splice(index, 1)
      //   }
      // })

      // 根据自定义的条件查找索引: findIndex
      // 调用这个方法也会循环数组, 有一个返回值是索引
      const index = this.list.findIndex((item) => item.id === id);
      this.list.splice(index, 1);
    },
    changeTaskHandler(isSel) {
      // console.log(isSel)
      this.isSel = isSel;
    },
    clearDoneHandler() {
      // 找到所有已完成的任务删除即可
      // 筛选出所有未完成的任务放入一个新数组中, 直接覆盖 list 原数组
      // this.list  = this.list.filter(item => !item.isDone)

      let newArr = [];
      this.list.forEach((item, index) => {
        if (!item.isDone) {
          newArr.push(item);
        }
      });
      this.list = newArr;

      // 找到所有已完成的任务, 将其删除
      // for (let i = 0; i < this.list.length; i++) {
      //   let item = this.list[i]
      //   if (item.isDone) {
      //     this.list.splice(i, 1)
      //     i--
      //   }
      // }

      // this.list.forEach((item, index) => {
      //   // 循环的过程中删除数据 下标会变化
      //   if (item.isDone) {
      //     this.list.splice(index, 1)
      //   }
      // })
    },
  },
  computed: {
    showList() {
      // 根据当前最新的状态来对 list 进行筛选
      if (this.isSel === "yes") {
        // filter 数组筛选/过滤
        // 返回一个新数组, 会将循环过程中符合条件的加入新数组最后返回
        // return this.list.filter(item => item.isDone)
        let newArr = [];
        // 如果当前是 yes 就把 isDone 为 true 的数据放到新数组中返回
        this.list.forEach((item) => {
          if (item.isDone) {
            newArr.push(item);
          }
        });
        return newArr;
      } else if (this.isSel === "no") {
        // return this.list.filter(item => !item.isDone)
        // 如果当前是 no 就把 isDone 为 false 的数据放到新数组中返回
        let newArr = [];
        this.list.forEach((item) => {
          if (!item.isDone) {
            newArr.push(item);
          }
        });
        return newArr;
      } else {
        // 如果当前是 all 就全部返回
        return this.list;
      }
    },
  },
  watch: {
    list: {
      deep: true,
      handler() {
        // 当数组的数据变化时存入本地
        localStorage.setItem("todolist", JSON.stringify(this.list));
      },
    },
  },
};
</script>

<style lang="scss" scoped>
</style>